<template>
  <div>
    <a-upload
      v-model:file-list="fileList"
      :accept="accept"
      :action="action"
      :before-upload="beforeUpload"
      :list-type="listType"
      :multiple="props.control?.config?.multiple"
      name="file"
      @change="handleChange"
      @preview="handlePreview">
      <template v-if="listType === 'picture-card'">
        <div v-if="control.config.maxCount == null || fileList.length < control.config.maxCount" class="text-gray-400">
          <upload-outlined/>
          <div class="mt-2">选择文件上传</div>
        </div>
      </template>
      <template v-else>
        <a-button :disabled="control.config.maxCount != null && fileList.length >= control.config.maxCount">
          <upload-outlined/>
          选择文件上传
        </a-button>
      </template>
    </a-upload>
    <a-modal v-model:visible="previewVisible"
             :footer="null"
             :title="previewTitle">
      <img v-if="previewUrl" :alt="previewTitle" :src="$files.resolve(previewUrl)" style="width: 100%"/>
    </a-modal>
  </div>
</template>
<script setup>
import {Form, Upload} from 'ant-design-vue';
import {UploadOutlined} from '@ant-design/icons-vue';
import config from "../../config.js";

const props = defineProps(['control', 'placeholder', 'value', 'initFiles']);
const emit = defineEmits(['update:value']);
const formItemContext = Form.useInjectFormItemContext();

const {
  control,
  placeholder,
  value
} = props;

const accept = computed(() => {
  return (control.config.accept ?? []).map(name => `.${name}`).join(',');
});

const action = computed(() => {
  return `/api/${control.config.uploadUrl.replace(/^\//, '')}`;
});

const listType = computed(() => {
  return control.config.listType ?? 'picture-card';
});

const nameKey = control.config.nameKey ?? 'originalFilename';
const valueKey = control.config.valueKey ?? 'id';
const pathKey = control.config.pathKey ?? 'path';
const fileList = ref([]);

const triggerChange = async () => {
  const value = fileList.value.filter(({status}) => status === 'done').map(file => file.response.url);
  emit('update:value', value);
  formItemContext.onFieldChange();
}

watch(() => props.initFiles, () => {
  fileList.value = [];
  props.initFiles.map(file => {
    const paths = file[pathKey]?.split(",");
    if (paths?.length > 0) {
      paths.forEach(path => {
        const resolvedPath = config.files.resolve(path);
        fileList.value.push({
          name: file[nameKey],
          percent: 100,
          status: 'done',
          thumbUrl: resolvedPath,
          response: file
        });
      });
    }
  });
}, {
  immediate: true
});

const handleChange = async ({file}) => {
  if (file.status === 'error') {
    file.error = file.response;
  } else if (['removed', 'done'].includes(file.status)) {
    await triggerChange();
  }
};

const beforeUpload = file => {
  const acceptConfig = control.config.accept;
  if (acceptConfig != null && !acceptConfig.some(ext => file.name.toLowerCase().endsWith(`.${ext.toLowerCase()}`))) {
    message.error(`文件格式仅支持 ${acceptConfig.map(name => `.${name}`).join('、')}`);
    return Upload.LIST_IGNORE;
  }
  const maxFileSize = control.config.maxFileSize ?? 100;
  if (file.size / 1024 > maxFileSize) {
    const maxSizeText = maxFileSize > 1024 ? (maxFileSize / 1024) + 'MB' : maxFileSize + 'KB'
    message.error(`文件大小不能超过 ${maxSizeText}`);
    return Upload.LIST_IGNORE;
  }
  return true;
};

const previewVisible = ref(false);
const previewTitle = ref(false);
const previewUrl = ref(null);
const handlePreview = async file => {
  const filename = file.name.toLowerCase();
  if (filename.endsWith('.jpg')
    || filename.endsWith('.png')
    || filename.endsWith('.gif')) {
    previewVisible.value = true;
    previewUrl.value = file.response[pathKey];
    previewTitle.value = file.response[nameKey];
  } else if (filename.endsWith('.pdf')) {
    window.open(config.files.resolve(file.response[pathKey]));
  }
};
</script>
